package soar.test.match;

import java.time.Instant;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Random;
import java.util.function.BinaryOperator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class App
{
    public static void main(String[] args)
    {
        new App().run();
    }

    private void run()
    {
        try
        {
            String split = "==================================================";
            System.out.println(split);

            split();
            System.out.println(split);

            matches();
            System.out.println(split);

            regex();
            System.out.println(split);

            tag();
            System.out.println(split);

            filter();
            System.out.println(split);

            performance();
            System.out.println(split);
        }
        catch (Exception e)
        {
            System.err.println(String.format("%s", e));
        }
    }

    private void split()
    {
        // String split = "----------------------------------------";

        System.out.println("split");
        System.out.println();

        String s;
        String regex;
        String[] arr;

        s = "   ";
        regex = ",";
        List<String> list = Arrays.asList(s.split(regex)).stream()
                .filter(x -> !x.trim().isEmpty()).collect(Collectors.toList());
        System.out.println(String.format("empty(%s) (%s) --> (%d)", s, regex,
                list.size()));

        s = "   aaa   bbb     ccc";
        regex = " +";
        arr = s.split(regex);
        System.out.println(String.format("%s (%s) --> (%s) (%s) (%s)", s, regex,
                arr[0], arr[1], arr[2]));

        s = "aaa.bbb.ccc";
        regex = "\\.";
        arr = s.split(regex);
        System.out.println(String.format("%s (%s) --> (%s) (%s) (%s)", s, regex,
                arr[0], arr[1], arr[2]));

        s = "aaa|bbb|ccc";
        regex = "\\|";
        arr = s.split(regex);
        System.out.println(String.format("%s (%s) --> %s) (%s) (%s)", s, regex,
                arr[0], arr[1], arr[2]));

        s = "aaa*bbb*ccc";
        regex = "\\*";
        arr = s.split(regex);
        System.out.println(String.format("%s (%s) --> (%s) (%s) (%s)", s, regex,
                arr[0], arr[1], arr[2]));

        s = "aaa,bbb,ccc";
        regex = ",";
        arr = s.split(regex); // "\\,"也可以
        System.out.println(String.format("%s (%s) --> (%s) (%s) (%s)", s, regex,
                arr[0], arr[1], arr[2]));

        s = "aaa/bbb/ccc";
        regex = "/";
        arr = s.split(regex); // "\\,"也可以
        System.out.println(String.format("%s (%s) --> %s", s, regex,
                Arrays.asList(arr).stream().map(x -> "(" + x + ")")
                        .collect(Collectors.joining(" "))));

        s = "aaaXbbbXccc";
        regex = "X";
        arr = s.split(regex);
        System.out.println(String.format("%s (%s) --> (%s) (%s) (%s)", s, regex,
                arr[0], arr[1], arr[2]));
        regex = "O";
        arr = s.split(regex);
        System.out.print(String.format("%s (%s) --> ", s, regex));
        for (String n : arr)
        {
            System.out.print(String.format("(%s) ", n));
        }
        System.out.println();
    }

    private void matches()
    {
        String split = "----------------------------------------";

        System.out.println("matches");
        System.out.println(split);

        String s = "Hello World 12/15";
        String reg = ".*[0-9][0-9]/[0-9][0-9]$";
        if (s.matches(reg))
        {
            System.out.println(String.format("(%s) match (%s)", s, reg));
        }
        System.out.println();

        System.out.println(split);

        s = "abcdefg+12345";
        String sub = "g+";
        if (s.contains(sub))
        {
            System.out.println(String.format("(%s) contains (%s)", s, sub));
        }
        s = "http://www.xxx.com";
        reg = "?";
        if (s.indexOf(reg) != -1)
        {
            System.out.println(String.format("(%s) contains (%s)", s, "?"));
        }
        s += "?a=1";
        if (s.indexOf(reg) != -1)
        {
            System.out.println(String.format("(%s) contains (%s)", s, "?"));
        }
        if (s.matches("\\?"))
        { // 错误
            System.out.println(String.format("(%s) matches (%s)", s, "?"));
        }
        if (s.matches(".*\\?.*"))
        {
            System.out
                    .println(String.format("(%s) matches (%s)", s, ".*\\?.*"));
        }
        s = "12345abcd甲乙丙丁";
        reg = "\\d+.*";
        if (s.matches(reg))
        {
            System.out.println(String.format("(%s) matches (%s)", s, reg));
        }
        s = "甲乙 12345abcd";
        reg = "甲乙.*\\s+.*"; // 开头非甲乙，无空格
        if (s.matches(reg))
        {
            System.out.println(String.format("(%s) matches (%s)", s, reg));
        }
        else
        {
            System.out.println(String.format("(%s) NOT matches (%s)", s, reg));
        }
    }

    private void regex() throws Exception
    {
        String split = "----------------------------------------";

        String keyword;

        System.out.println("Regular Expression");
        System.out.println();

        String s = " application/json; charset = UTF-8";
        System.out.println("source: " + s);
        Pattern pattern = Pattern.compile(
                ".*application/(\\w*).*charset *= *([A-Za-z_\\-0-9]+).*");
        Matcher matcher = pattern.matcher(s);
        if (matcher.matches())
        {
            for (int i = 1; i <= matcher.groupCount(); i++)
            {
                System.out.println("group " + i + ": " + matcher.group(i));
            }
        }

        System.out.println(split);

        System.out.println("find");
        System.out.println();

        s = "<html><a>xxx</a><a><font/><img url=\"a.jpg\"/></a></html>";
        System.out.println("source: " + s);
        matcher = Pattern.compile("<a[^>]*>(.*?)</a>").matcher(s);
        while (matcher.find())
        {
            System.out.println("group: " + matcher.group());
            for (int i = 1; i <= matcher.groupCount(); i++)
            {
                System.out.println("group " + i + ": " + matcher.group(i));
            }
        }
        System.out.println();

        s = "火箭Rocket ROCK火箭";
        keyword = "rock";
        matcher = Pattern.compile("(?i)" + keyword).matcher(s);
        while (matcher.find())
        {
            System.out.println(String.format("(%s) find (%s): %s", s, keyword,
                    matcher.group()));
        }

        System.out.println(split);

        System.out.println("replace");
        System.out.println();

        s = "2015-01-23";
        String s2 = Pattern.compile("-").matcher(s).replaceAll("/");
        System.out.println("简单替换\n" + s + " -> " + s2);
        System.out.println();

        s = "xxx x1a12 b34 sadfa c5678 d7777 xxx yyy11";
        s2 = Pattern.compile("\\b[a-zA-Z]+(\\d+)\\b").matcher(s)
                .replaceAll("$1");
        System.out.println("字母+数字去掉字母\n" + s + " -> " + s2);
        System.out.println();

        s = "开始" + " Huawei and huawei and HUAWEI and huaWei and HuaWei"
                + " and ZhongXin and zhongxin and ZHONGXIN and Zhongxin and ZhongXIN"
                + " 结束";
        keyword = "Huawei";
        s2 = Pattern.compile(keyword, Pattern.CASE_INSENSITIVE).matcher(s)
                .replaceAll("<<$0>>");
        System.out.println("不区分大小写替换\n" + s + "\n->\n" + s2);

        System.out.println(split);

        String ncr = "BISS(&#12288;&#160;)&#19978;&#28023;&#32418;&#26143;&#20892;&#22330;&#32844;&#24037;&#20013;&#31561;&#23398;&#26657;-- &# ;(&#21271;&#33489;&#26657;&#21306;)";
        ncr += "&#32;"; // 空格，避免结尾不匹配
        matcher = Pattern.compile("(.*?)&#([0-9]+);").matcher(ncr);
        StringBuilder strbld = new StringBuilder();
        while (matcher.find())
        {
            strbld.append(matcher.group(1));
            strbld.append((char) Integer.parseInt(matcher.group(2)));
        }
        System.out.println("NCR: " + ncr);
        System.out.println("中文: " + strbld.toString().trim());
        System.out.println("替换成普通空格: " + strbld.toString()
                .replace("\u3000", " ").replace("\u00a0", " ").trim());

        System.out.println(split);

        System.out.println("是否包含汉字");
        System.out.println();

        s = "《》“”abc上海.8sasf***虹口98adfs../";
        // s.matches(pattern) Patter.matches(pattern, s) 都必须全部匹配
        if (Pattern.compile("[\\u4e00-\\u9fa5]").matcher(s).find())
        {
            System.out.println(String.format("%s -> 包含汉字", s));
        }
        Matcher m = Pattern.compile("[\\u4e00-\\u9fa5]").matcher(s);
        int count = 0;
        while (m.find())
        {
            System.out.println(String.format("%s", m.group()));
            count++;
        }
        System.out.println(String.format("%s -> %d个汉字", s, count));

        System.out.println(split);

        System.out.println("去除非文本字符");
        System.out.println();

        s = "123\n456\t789'abc\"def\\ghi";
        s2 = Pattern.compile("[\\u0001-\\u0020\\u007f\'\"\\\\]").matcher(s)
                .replaceAll("|");
        System.out.println(String.format("%s -> %s", s, s2));

        System.out.println(split);

        System.out.println("去除HTML标签");
        System.out.println();

        s = "<p>标题&rdquo;拉塞尔写道。***   ###---...</p>";
        s2 = s;
        s2 = Arrays.asList("<.*?>", "&.*?;").stream().reduce(s2,
                (sum, p) -> Pattern.compile(String.format("%s", p)).matcher(sum)
                        .replaceAll(""));
        // s2 = Pattern.compile("<.*?>").matcher(s).replaceAll("");
        // s2 = Pattern.compile("&.*?;").matcher(s2).replaceAll("");
        s2 = Arrays.asList("*", " ", "#", "-", ".").stream().reduce(s2,
                (sum, p) -> Pattern.compile(String.format("([%s])+", p))
                        .matcher(sum).replaceAll("$1"));
        // s2 = Pattern.compile("([*])+").matcher(s2).replaceAll("$1");
        // s2 = Pattern.compile("([ ])+").matcher(s2).replaceAll("$1");
        // s2 = Pattern.compile("([#])+").matcher(s2).replaceAll("$1");
        // s2 = Pattern.compile("([-])+").matcher(s2).replaceAll("$1");
        // s2 = Pattern.compile("([.])+").matcher(s2).replaceAll("$1");
        System.out.println(String.format("%s -> %s", s, s2));

        System.out.println(split);

        s = "梅赛德斯奔驰C300，奔驰c500";
        s2 = Pattern
                .compile("(奔驰|C)", Pattern.CASE_INSENSITIVE)
                .matcher(s).replaceAll("<font color='red'>$1</font>");
        System.out.println(String.format("%s -> %s", s, s2));
    }

    private void tag() throws Exception
    {
        String split = "----------------------------------------";

        System.out.println("tag");
        System.out.println();
        System.out.println(split);

        final String s = "{\"id\":100,\"name\":\"甲\",\"phone\":["
                + "{\"type\":\"home\",\"number\":[1111,2222]},"
                + "{\"type\":\"work\",\"number\":[88888,99999]}" + "]}";
        System.out.println(String.format("%s", s));
        System.out.println();

        int from_index = 0;
        Map<String, Integer> indexes = find_match_tag(s, from_index, "[", "]");
        Optional<Map<String, Integer>> opt = Optional.ofNullable(indexes);
        opt.orElseThrow(() -> {
            return new Exception("index");
        });
        opt.ifPresent(x -> {
            System.out.println(String.format("[]: left(%d) right(%d)",
                    x.get("left"), x.get("right")));
            System.out.println(String.format("substring: %s",
                    s.substring(x.get("left"), x.get("right"))));
        });
        System.out.println();

        from_index = indexes.get("left") + 1;
        while (true)
        {
            indexes = find_match_tag(s, from_index, "[", "]");
            if (indexes == null)
            {
                System.out.println("cannot find [...], stop");
                break;
            }
            System.out.println(String.format("[]: left(%d) right(%d)",
                    indexes.get("left"), indexes.get("right")));
            System.out.println(String.format("substring: %s",
                    s.substring(indexes.get("left"), indexes.get("right"))));
            System.out.println();
            from_index = indexes.get("right");
        }

        System.out.println(split);

        String html = "<ul id=\"schoolCityQuList\" class=\"module-qulist\">"
                + "\n"
                + "<li><a href=\"#highschool_anchor\"  onclick=\"SchoolComponent.tihuan('city_qu_310101')\">&#40644;&#28006;&#21306;</a></li>"
                + "\n"
                + "<li><a href=\"#highschool_anchor\"  onclick=\"SchoolComponent.tihuan('city_qu_310103')\">&#21346;&#28286;&#21306;</a></li>"
                + "\n"
                + "<li><a href=\"#highschool_anchor\"  onclick=\"SchoolComponent.tihuan('city_qu_310104')\">&#24464;&#27719;&#21306;</a></li>"
                + "\n"
                + "<li><a href=\"#highschool_anchor\"  onclick=\"SchoolComponent.tihuan('city_qu_310105')\">&#38271;&#23425;&#21306;</a></li>"
                + "\n"
                + "<li><a href=\"#highschool_anchor\"  onclick=\"SchoolComponent.tihuan('city_qu_310106')\">&#38745;&#23433;&#21306;</a></li>"
                + "\n" + "</ul>" + "\n";
        System.out.println(String.format("%s", html));
        System.out.println();

        from_index = 0;
        while (true)
        {
            indexes = find_match_tag(html, from_index, "<li>", "</li>");
            if (indexes == null)
            {
                break;
            }
            System.out.println(String.format("substring: %s",
                    html.substring(indexes.get("left"), indexes.get("right"))));
            from_index = indexes.get("right");
        }
    }

    private Map<String, Integer> find_match_tag(String s, int from_index,
            String left_tag, String right_tag)
    {
        int left_index = -1;
        int right_index = -1;

        int match_count = 0;
        int index = from_index;
        while (index < s.length())
        {
            if (s.startsWith(left_tag, index))
            {
                if (match_count == 0)
                {
                    left_index = index;
                }
                match_count++;
                index += left_tag.length();
            }
            else if (s.startsWith(right_tag, index))
            {
                if (match_count == 0)
                {

                }
                else
                {
                    match_count--;
                    if (match_count == 0)
                    {
                        right_index = index + right_tag.length();
                        Map<String, Integer> indexes = new HashMap<>();
                        indexes.put("left", left_index);
                        indexes.put("right", right_index);
                        return indexes;
                    }
                }
                index += right_tag.length();
            }
            else
            {
                index++;
            }
        }

        return null;
    }

    private void filter()
    {
        String s = "nba 湖人 中超 上港 中超 哈登 湖人";
        System.out.println("Orig: " + s);
        List<String> league_list = Arrays.asList("nba", "cba", "中超");
        List<String> team_list = Arrays.asList("恒大", "上港", "湖人");

        String sf = s;
        BinaryOperator<String> operator = (f, x) -> {
            return f.replaceAll(x, "").trim();
        };
        sf = league_list.stream().reduce(sf, operator);
        System.out.println(String.format("filter(%s): %s",
                league_list.stream().collect(Collectors.joining(", ")), sf));
        sf = team_list.stream().reduce(sf, operator);
        System.out.println(String.format("filter(%s): %s",
                team_list.stream().collect(Collectors.joining(", ")), sf));
    }

    private void performance()
    {
        String split = "----------------------------------------";

        System.out.println("性能测试");
        System.out.println();
        System.out.println(split);

        long begin_time;
        long count;
        long cost;

        System.out.println("生成随机字符串");
        System.out.println();
        begin_time = Instant.now().toEpochMilli();
        String code = "东风";
        String[] source = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
                "A", "B", "C", "D", "E", "F", code };
        int num = 5000000;
        Random random = new Random();
        List<String> strs = Stream
                .generate(() -> Stream
                        .generate(() -> random.nextInt(source.length))
                        .limit(random.nextInt(10) + 10).map(x -> source[x])
                        .collect(Collectors.joining()))
                .limit(num).collect(Collectors.toList());
        System.out.println(String.format("共%,d条，耗时%,d毫秒", num,
                Instant.now().toEpochMilli() - begin_time));

        System.out.println(split);

        System.out.println("转换成小写");
        System.out.println();
        begin_time = Instant.now().toEpochMilli();
        List<String> strs_lc = strs.stream().map(String::toLowerCase)
                .collect(Collectors.toList());
        cost = Instant.now().toEpochMilli() - begin_time;
        System.out.println(
                String.format("耗时%,d毫秒，%,d条/秒", cost, num * 1000L / cost));

        System.out.println(split);

        System.out.println("匹配");
        System.out.println();

        System.out.println(String.format("contains(\"%s\")", code));
        count = strs_lc.stream().filter(s -> s.contains(code)).count();
        cost = Instant.now().toEpochMilli() - begin_time;
        System.out.println(String.format("共%,d条，耗时%,d毫秒，%,d条/秒", count, cost,
                num * 1000L / cost));

        System.out.println();

        String match = String.format(".*%s.*", code);
        System.out.println(String.format("matches(\"%s\")", match));
        count = strs_lc.stream().filter(s -> s.matches(match)).count();
        cost = Instant.now().toEpochMilli() - begin_time;
        System.out.println(String.format("共%,d条，耗时%,d毫秒，%,d条/秒", count, cost,
                num * 1000L / cost));

        System.out.println();

        System.out
                .println(String.format("pattern.matcher(\"%s\").find()", code));
        Pattern pattern = Pattern.compile(code);
        count = strs_lc.stream().filter(s -> pattern.matcher(s).find()).count();
        cost = Instant.now().toEpochMilli() - begin_time;
        System.out.println(String.format("共%,d条，耗时%,d毫秒，%,d条/秒", count, cost,
                num * 1000L / cost));
    }

}
